package CTCOffice;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Stack;

import TrackModel.StationBlock;
import application.Main;


public class Router {
	public static HashMap<String,ArrayList<StationBlock>> routes = new HashMap<String, ArrayList<StationBlock>>();
	
	//Generates the route based on a depth first search
	//Results must be checked against null to see if routing failed or not
	public static ArrayList<Integer> route(String line, StationBlock start, StationBlock end) {
		Stack<StationBlock> route = dfs(line, start, end);
		//Stack<StationBlock> route = getRoute(line, start, end);
		
		if(!route.isEmpty()) {
			ArrayList<Integer> reverse = new ArrayList<Integer>();
			while(!route.isEmpty()) {
				reverse.add(route.pop().getBlockID());
			}

			return reverse;
		}

		return null;
	}

	/**
	 * This function performs a basic implementation of a depth first search utilizing a stack. In a network of connected stations
	 * it should be possible to iterate over all of the available valid connections at each station and obtain a route.
	 * 
	 * @param line The color of the line, for getting stations
	 * @param start The first station on the line
	 * @param end The ending "goal" station
	 * @return A stack containing the inverse of the route from start -> end
	 */
	private static Stack<StationBlock> dfs(String line, StationBlock start, StationBlock end) {
		Stack<StationBlock> route = new Stack<StationBlock>();
		//ArrayList<Integer> blocker = new ArrayList<Integer>();

		route.push(start);
		
		while(!route.isEmpty())	{
			StationBlock current = (StationBlock)route.pop();
			//StationBlock prev = null;
			
			//Checks if we have finished routing
			if(current.getBlockID() == end.getBlockID()) {
				route.push(current);
				break;
			}
			
			//Checks to see if we can go deeper in our search
			if(current.getConnectingStations().length != 0)
				route.push(current);
			else
				continue;
			
			//Performs all of the next blocks gathering
			for(int s : current.getConnectingStations()) {
				StationBlock sbnext = (StationBlock)Main.trackModel.getLine(line).getStations().get(s);
				route.add(sbnext);
			}
		}
		
		Stack<StationBlock> reverse = new Stack<StationBlock>();
		while(!route.isEmpty())
			reverse.push(route.pop());

		return reverse;
	}
	
	public static ArrayList<StationBlock> getRoute(String line, String start, String end) {
		ArrayList<StationBlock> stations = routes.get(line);
		Stack<StationBlock> route = new Stack<StationBlock>();
		
		int i = 0;
		for(; i < stations.size(); i++)
			if(stations.get(i).getStationName() == start)
				break;
		//Pushes on the start station
		route.push(stations.get(i));
		
		int pos = (i + 1) % stations.size();
		//Gets the remaining stations in between
		while(pos != i) {
			route.push(stations.get(pos));
			//Checks for the end of the route
			if(stations.get(pos).getStationName() == end)
				break;
			
			pos = (pos + 1) % stations.size();
		}
		
		//Reverse the route
		ArrayList<StationBlock> finalRoute = new ArrayList<StationBlock>();
		Stack<StationBlock> flop = new Stack<StationBlock>();
		while(!route.isEmpty())
			flop.push(route.pop());
		while(!flop.isEmpty())
			finalRoute.add(flop.pop());
		
		return finalRoute;
	}
	
	public static void addRoute(String name) {
		routes.put(name, new ArrayList<StationBlock>());
	}
}